////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009 Daniel F. Hanson
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////

using System.Collections.Generic;

#if DEBUG
using System.Diagnostics;
#endif

namespace SilverLua.Compiler
{
   internal class IfStatementNode : StatementNode
   {
      private ExpressionNode[] _conditions;
      private StatementNode[][] _blocks;
      
      internal IfStatementNode(ExpressionNode[] conditions, StatementNode[][] blocks)
      {
         #if DEBUG
         Debug.Assert(conditions.Length >= 1);
         Debug.Assert(blocks.Length - conditions.Length == 0 ||
                      blocks.Length - conditions.Length == 1);
         #endif
         
         _conditions = conditions;
         _blocks = blocks;
      }

      internal override void GenerateInstructions(Parser parser, int currentChunk)
      {
         List<Instruction> instructionList = parser.ChunkList[currentChunk].Instructions;
         List<int> endOfBlockJumps = new List<int>();
         int conditionRegister = parser.ChunkList[currentChunk].AllocateTempRegister();
         
         for (int i = 0; i < _conditions.Length; ++i)
         {
            _conditions[i].EvaluateTo(conditionRegister, parser, currentChunk);
            int cjmpIndex = instructionList.Count;
            instructionList.Add(new Instruction(Opcode.ConditionalJump,
                                                new[] { OperandType.IntegerLiteral,
                                                        OperandType.Value,
                                                        OperandType.BooleanLiteral },
                                                new[] { 0,
                                                        conditionRegister,
                                                        0 }));

            foreach (StatementNode stmt in _blocks[i])
            {
               stmt.GenerateInstructions(parser, currentChunk);
            }
            
            if (_blocks.Length > i + 1)
            {
               int index = instructionList.Count;
               endOfBlockJumps.Add(index);
               instructionList.Add(new Instruction(Opcode.Jump,
                                                   new[] { OperandType.IntegerLiteral },
                                                   new[] { index }));
            }

            instructionList[cjmpIndex].OperandValues[0] = instructionList.Count - cjmpIndex - 1;
         }
         
         if (_blocks.Length > _conditions.Length)
         {
            foreach (StatementNode stmt in _blocks[_blocks.Length - 1])
            {
               stmt.GenerateInstructions(parser, currentChunk);
            }
         }
         
         foreach (int index in endOfBlockJumps)
         {
            instructionList[index].OperandValues[0] = instructionList.Count - index - 1;
         }
      }
   }
}
